package cz.muni.fi.pa165.sme.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import cz.muni.fi.pa165.sme.dao.api.UserDao;
import cz.muni.fi.pa165.sme.dao.entity.User;
import cz.muni.fi.pa165.sme.dao.exception.DataStorageOperationException;
import org.springframework.stereotype.Repository;

import static cz.muni.fi.pa165.sme.common.EntityValidator.validateDeleteEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateEntityManager;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateGetEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateNewEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateUpdatedEntity;

/**
 * @author forman
 */
@Repository
public class UserDaoImpl implements UserDao {

    @PersistenceContext
    private EntityManager entityManager;

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void createUser(User user) {
        validateEntityManager(entityManager);
        validateNewEntity(user);

        try{
            entityManager.persist(user);
        }catch (PersistenceException e){
            throw new DataStorageOperationException("An error has occurred while inserting a new user " +
                    "object to the database",e);
        }
        entityManager.flush();
    }

    @Override
    public void updateUser(User user) {
        validateEntityManager(entityManager);
        validateUpdatedEntity(user);

        try{
            entityManager.merge(user);
        } catch (PersistenceException e){
            throw new DataStorageOperationException("An error has occurred while updating User entity in database",e);
        } catch (IllegalArgumentException e){
            throw new DataStorageOperationException("User: " + user + " has wrong argument",e);
        }}

    @Override
    public User getUser(Long id) {
        validateGetEntity(id);

        validateEntityManager(entityManager);

        try{
            return entityManager.find(User.class, id);
        } catch (PersistenceException ex) {
            throw new DataStorageOperationException("An error has occured when looking for a User entity in database.", ex);
        }
    }

    @Override
    public void deleteUser(User user) {
        validateEntityManager(entityManager);
        validateDeleteEntity(user);

        try{
            User existingUser = entityManager.find(User.class, user.getId());
            if(existingUser == null){
                throw new IllegalArgumentException("User with id " + user.getId() + " has not been found in the databse");
            }
            entityManager.remove(existingUser);
        }catch (PersistenceException e){
            throw new DataStorageOperationException("An error has occurred while deleting user entity from " +
                    "the database",e);
        }
    }

    @Override
    public List<User> findAllUser() {
        validateEntityManager(entityManager);

        try{
            TypedQuery<User> namedQuery = entityManager.createNamedQuery(User.FIND_ALL_USERS, User.class);
            return namedQuery.getResultList();
        } catch (PersistenceException ex) {
            throw new DataStorageOperationException("An error has occurred when looking for a user entity in database.", ex);
        }
    }

	@Override
	public User getUserByLogin(final String login) {
		validateEntityManager(entityManager);

		try{
			TypedQuery<User> selectByLogin = entityManager.createNamedQuery(User.FIND_BY_LOGIN, User.class);
			selectByLogin.setParameter("login", login);
			try {
				return selectByLogin.getSingleResult();
			} catch (NoResultException ex) {
				return null;
			}
		} catch (PersistenceException ex) {
			throw new DataStorageOperationException("An error has occurred when looking for a user by login "+ login, ex);
		}
	}
}
